home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / System / AsyncioPPC / source / async.c < prev    next >
C/C++ Source or Header  |  2000-05-10  |  13KB  |  504 lines

  1. #include <pragma/dos_lib.h>
  2. #include <pragma/exec_lib.h>
  3. #include <libraries/asyncio.h>
  4. #include <exec/memory.h>
  5. #include <string.h>
  6.  
  7. #define D_S(type,name) char a_##name[ sizeof( type )+3]; type *name=(type *)((LONG)(a_##name+3)&~3);
  8.  
  9. #ifndef MIN
  10. #define MIN(a,b) ((a)<(b)?(a):(b))
  11. #endif
  12.  
  13. static VOID AS_SendPacket(struct AsyncFile *file,APTR arg2)
  14. {
  15. file->af_Packet.sp_Pkt.dp_Port=&file->af_PacketPort;
  16. file->af_Packet.sp_Pkt.dp_Arg2=(LONG)arg2;
  17. PutMsg(file->af_Handler,&file->af_Packet.sp_Msg);
  18. file->af_PacketPending=TRUE;
  19. }
  20.  
  21. static LONG AS_WaitPacket(AsyncFile *file)
  22. {
  23. LONG bytes;
  24. if(file->af_PacketPending)
  25.     {
  26.     while(TRUE)
  27.         {
  28.         file->af_PacketPort.mp_Flags=PA_SIGNAL;
  29.         Remove((struct Node *)WaitPort(&file->af_PacketPort));
  30.         file->af_PacketPort.mp_Flags=PA_IGNORE;
  31.         file->af_PacketPending=FALSE;
  32.         bytes=file->af_Packet.sp_Pkt.dp_Res1;
  33.         if(bytes>=0) return bytes;
  34.         if(ErrorReport(file->af_Packet.sp_Pkt.dp_Res2,REPORT_STREAM,file->af_File,NULL)) return -1;
  35.         AS_SendPacket(file,file->af_Buffers[file->af_ReadMode?file->af_CurrentBuf:1-file->af_CurrentBuf]);
  36.         }
  37.     }
  38. SetIoErr(file->af_Packet.sp_Pkt.dp_Res2);
  39. return file->af_Packet.sp_Pkt.dp_Res1;
  40. }
  41.  
  42. static VOID AS_RecordSyncFailure(struct AsyncFile *file)
  43. {
  44. file->af_LastRes1=file->af_Packet.sp_Pkt.dp_Res1;
  45. file->af_LastBytesLeft=file->af_BytesLeft;
  46. file->af_Packet.sp_Pkt.dp_Res1=-1;
  47. file->af_Packet.sp_Pkt.dp_Res2=IoErr();
  48. file->af_BytesLeft=0;
  49. }
  50.  
  51. static VOID AS_RequeuePacket(AsyncFile *file)
  52. {
  53. AddHead(&file->af_PacketPort.mp_MsgList,&file->af_Packet.sp_Msg.mn_Node);
  54. file->af_PacketPending=TRUE;
  55. }
  56.  
  57. AsyncFile *AS_OpenAsyncFH(BPTR handle,LONG mode,LONG bufferSize,BOOL closeIt)
  58. {
  59. FileHandle *fh;
  60. AsyncFile *file=NULL;
  61. BPTR    lock=NULL;
  62. LONG    blockSize,blockSize2;
  63. D_S(struct InfoData,infoData);
  64. if(mode==MODE_READ)
  65.     {
  66.     if(handle) lock=DupLockFromFH(handle);
  67.     }
  68. else
  69.     {
  70.     if(mode==MODE_APPEND)
  71.         {
  72.         if(handle)
  73.             {
  74.             if(Seek(handle,0,OFFSET_END)<0)
  75.                 {
  76.                 if(closeIt) Close(handle);
  77.                 handle=NULL;
  78.                 }
  79.             }
  80.         }
  81.     if(handle) lock=ParentOfFH(handle);
  82.     }
  83. if(handle)
  84.     {
  85.     blockSize=512;
  86.     blockSize2=1024;
  87.     if(lock)
  88.         {
  89.         if(Info(lock,infoData))
  90.             {
  91.             blockSize=infoData->id_BytesPerBlock;
  92.             blockSize2=blockSize*2;
  93.             bufferSize=((bufferSize+blockSize2-1)/blockSize2)*blockSize2;
  94.             }
  95.         UnLock(lock);
  96.         }
  97.     for(;;)
  98.         {
  99.         if(file=(AsyncFile *)AllocVec(sizeof(AsyncFile)+bufferSize+15,MEMF_PUBLIC|MEMF_ANY)) break;
  100.         else
  101.             {
  102.             if(bufferSize>blockSize2)bufferSize-=blockSize2;
  103.             else break;
  104.             }
  105.         }
  106.     if(file)
  107.         {
  108.         file->af_File=handle;
  109.         file->af_ReadMode=(mode==MODE_READ);
  110.         file->af_BlockSize=blockSize;
  111.         file->af_CloseFH=closeIt;
  112.         fh=(FileHandle *)BADDR(file->af_File);
  113.         file->af_Handler=fh->fh_Type;
  114.         file->af_BufferSize=(ULONG)bufferSize/2;
  115.         file->af_Buffers[0]=(UBYTE *)(((ULONG)file+sizeof(AsyncFile)+15)&0xfffffff0);
  116.         file->af_Buffers[1]=file->af_Buffers[0]+file->af_BufferSize;
  117.         file->af_CurrentBuf=0;
  118.         file->af_SeekOffset=0;
  119.         file->af_PacketPending=FALSE;
  120.         file->af_SeekPastEOF=FALSE;
  121.         file->af_PacketPort.mp_MsgList.lh_Head=(struct Node *)&file->af_PacketPort.mp_MsgList.lh_Tail;
  122.         file->af_PacketPort.mp_MsgList.lh_Tail=NULL;
  123.         file->af_PacketPort.mp_MsgList.lh_TailPred=(struct Node *)&file->af_PacketPort.mp_MsgList.lh_Head;
  124.         file->af_PacketPort.mp_Node.ln_Type=NT_MSGPORT;
  125.         file->af_PacketPort.mp_Node.ln_Name=NULL;
  126.         file->af_PacketPort.mp_Flags=PA_IGNORE;
  127.         file->af_PacketPort.mp_SigBit=SIGB_SINGLE;
  128.         file->af_PacketPort.mp_SigTask=FindTask(NULL);
  129.         file->af_Packet.sp_Pkt.dp_Link=&file->af_Packet.sp_Msg;
  130.         file->af_Packet.sp_Pkt.dp_Arg1=fh->fh_Arg1;
  131.         file->af_Packet.sp_Pkt.dp_Arg3=file->af_BufferSize;
  132.         file->af_Packet.sp_Pkt.dp_Res1=0;
  133.         file->af_Packet.sp_Pkt.dp_Res2=0;
  134.         file->af_Packet.sp_Msg.mn_Node.ln_Name=(STRPTR)&file->af_Packet.sp_Pkt;
  135.         file->af_Packet.sp_Msg.mn_Node.ln_Type=NT_MESSAGE;
  136.         file->af_Packet.sp_Msg.mn_Length=sizeof(struct StandardPacket);
  137.         if(mode==MODE_READ)
  138.             {
  139.             file->af_Packet.sp_Pkt.dp_Type=ACTION_READ;
  140.             file->af_BytesLeft=0;
  141.             file->af_Offset=file->af_Buffers[1];
  142.             if(file->af_Handler) AS_SendPacket(file,file->af_Buffers[0]);
  143.             }
  144.         else
  145.             {
  146.             file->af_Packet.sp_Pkt.dp_Type=ACTION_WRITE;
  147.             file->af_BytesLeft=file->af_BufferSize;
  148.             file->af_Offset=file->af_Buffers[0];
  149.             }
  150.         }
  151.     else
  152.         {
  153.         if(closeIt) Close(handle);
  154.         }
  155.     }
  156. return file;
  157. }
  158.  
  159. struct AsyncFile *OpenAsync(register __a0 STRPTR fileName,register __d0 LONG mode,register __d1 LONG bufferSize,register __a6 struct AsyncIOBase *base)
  160. {
  161. static const WORD PrivateOpenModes[]={MODE_OLDFILE,MODE_NEWFILE,MODE_READWRITE};
  162. BPTR handle;
  163. AsyncFile *file=NULL;
  164. if(handle=Open(fileName,PrivateOpenModes[mode]))
  165.     {
  166.     if(!(file=AS_OpenAsyncFH(handle,mode,bufferSize,TRUE)))Close(handle);
  167.     }
  168. return file;
  169. }
  170.  
  171. struct AsyncFile *OpenAsyncFromFH(register __a0 BPTR handle,register __d0 LONG mode,register __d1 LONG bufferSize,register __a6 struct AsyncIOBase *base)
  172. {
  173. return AS_OpenAsyncFH(handle,mode,bufferSize,FALSE);
  174. }
  175.  
  176. LONG CloseAsync(register __a0 struct AsyncFile *file,register __a6 struct AsyncIOBase *base)
  177. {
  178. LONG    result;
  179. if(file)
  180.     {
  181.     result=AS_WaitPacket(file);
  182.     if(result>=0)
  183.         {
  184.         if(!file->af_ReadMode)
  185.             {
  186.             if(file->af_BufferSize>file->af_BytesLeft)
  187.                 {
  188.                 result=Write(file->af_File,file->af_Buffers[file->af_CurrentBuf],file->af_BufferSize-file->af_BytesLeft);
  189.                 }
  190.             }
  191.         }
  192.     if(file->af_CloseFH) Close(file->af_File);
  193.     FreeVec(file);
  194.     }
  195. else result=-1;
  196. return result;
  197. }
  198.  
  199. LONG ReadAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base)
  200. {
  201. LONG totalBytes=0;
  202. LONG bytesArrived;
  203. while(numBytes>file->af_BytesLeft)
  204.     {
  205.     CopyMem(file->af_Offset,buffer,file->af_BytesLeft);
  206.     numBytes-=file->af_BytesLeft;
  207.     buffer=(APTR)((ULONG)buffer+file->af_BytesLeft);
  208.     totalBytes+=file->af_BytesLeft;
  209.     file->af_BytesLeft=0;
  210.     bytesArrived=AS_WaitPacket(file);
  211.     if(bytesArrived<=0)
  212.         {
  213.         if(bytesArrived==0) return(totalBytes);
  214.         return -1;
  215.         }
  216.     AS_SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]);
  217.     if(file->af_SeekOffset>bytesArrived) file->af_SeekOffset=bytesArrived;
  218.     file->af_Offset=file->af_Buffers[file->af_CurrentBuf]+file->af_SeekOffset;
  219.     file->af_CurrentBuf=1-file->af_CurrentBuf;
  220.     file->af_BytesLeft=bytesArrived-file->af_SeekOffset;
  221.     file->af_SeekOffset=0;
  222.     }
  223. CopyMem(file->af_Offset,buffer,numBytes);
  224. file->af_BytesLeft-=numBytes;
  225. file->af_Offset+=numBytes;
  226. return totalBytes+numBytes;
  227. }
  228.  
  229. LONG PeekAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base)
  230. {
  231. if(!file->af_BytesLeft)
  232.     {
  233.     LONG bytes;
  234.     if((bytes=ReadAsync(file,&bytes,1,base))<=0) return bytes;
  235.     --file->af_Offset;
  236.     ++file->af_BytesLeft;
  237.     }
  238. numBytes=MIN(numBytes,file->af_BytesLeft);
  239. CopyMem(file->af_Offset,buffer,numBytes);
  240. return numBytes;
  241. }
  242.  
  243. LONG ReadCharAsync(register __a0 AsyncFile *file,register __a6 struct AsyncIOBase *base)
  244. {
  245. UBYTE    ch;
  246. if(file->af_BytesLeft)
  247.     {
  248.     ch=*file->af_Offset;
  249.     --file->af_BytesLeft;
  250.     ++file->af_Offset;
  251.     return ch;
  252.     }
  253. if(ReadAsync(file,&ch,1,base)>0) return ch;
  254. return -1;
  255. }
  256.  
  257. STRPTR FGetsLenAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR buf,register __d0 LONG numBytes,register __a2 LONG *len,register __a6 struct AsyncIOBase *base)
  258. {
  259. UBYTE *p;
  260. LONG    length=0;
  261. p=(UBYTE *)buf;
  262. if(--numBytes<=0) return 0;
  263. while(TRUE)
  264.     {
  265.     UBYTE *ptr;
  266.     LONG i,count;
  267.     ptr=(UBYTE *)file->af_Offset;
  268.     if(count=file->af_BytesLeft)
  269.         {
  270.         count=MIN(count,numBytes);
  271.         for(i=0;(i<count)&&(*ptr!='\n');++i) *p++=*ptr++;
  272.         length+=i;
  273.         if(i<count)
  274.             {
  275.             *p++='\n';
  276.             ++i;
  277.             length+=1;
  278.             }
  279.         file->af_BytesLeft-=i;
  280.         file->af_Offset+=i;
  281.         if((i>=numBytes)||(*(p-1)=='\n')) break;
  282.         numBytes-=i;
  283.         }
  284.     if(ReadAsync(file,p,1,base)<1) break;
  285.     --numBytes;
  286.     ++length;
  287.     if(*p++=='\n') break;
  288.     }
  289. *p='\0';
  290. *len=length;
  291. if(p==(UBYTE *)buf) return 0;
  292. return buf;
  293. }
  294.  
  295. STRPTR FGetsAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR buf,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base)
  296. {
  297. LONG len;
  298. return FGetsLenAsync(file,buf,numBytes,&len,base);
  299. }
  300.  
  301. LONG ReadLineAsync(register __a0 AsyncFile *file,register __a1 APTR buffer,register __d0 LONG bufSize,register __a6 struct AsyncIOBase *base)
  302. {
  303. LONG    len;
  304. if(FGetsLenAsync(file,buffer,bufSize,&len,base))
  305.     {
  306.     UBYTE *end;
  307.     end=((UBYTE *)buffer)+len-1;
  308.     if(*end!='\n')
  309.         {
  310.         UBYTE    ch=0;
  311.         while(TRUE)
  312.             {
  313.             UBYTE *ptr;
  314.             LONG i,count;
  315.             ptr=(UBYTE *)file->af_Offset;
  316.             if(count=file->af_BytesLeft)
  317.                 {
  318.                 for(i=0;(i<count)&& (*ptr!='\n');++i,++ptr)
  319.                     {
  320.                     }
  321.                 if(i<count)
  322.                     {
  323.                     ch='\n';
  324.                     ++i;
  325.                     }
  326.                 file->af_BytesLeft-=i;
  327.                 file->af_Offset+=i;
  328.                 if(i<count) break;
  329.                 }
  330.             if(ReadAsync(file,&ch,1,base)<1) break;
  331.             if(ch=='\n') break;
  332.             }
  333.         if(ch=='\n')
  334.             {
  335.             *end++='\n';
  336.             *end='\0';
  337.             }
  338.         }
  339.     }
  340. return len;
  341. }
  342.  
  343. static ULONG GetFileSize(AsyncFile *file,LONG *size)
  344. {
  345. D_S(struct FileInfoBlock,fib);
  346. if(!ExamineFH(file->af_File,fib))
  347.     {
  348.     AS_RecordSyncFailure(file);
  349.     return FALSE;
  350.     }
  351. *size=fib->fib_Size;
  352. return TRUE;
  353. }
  354.  
  355. LONG SeekAsync(register __a0 struct AsyncFile *file,register __d0 LONG position,register __d1 LONG mode,register __a6 struct AsyncIOBase *base)
  356. {
  357. LONG current,target,roundTarget,filePos;
  358. LONG minBuf,maxBuf,bytesArrived,diff;
  359. LONG fileSize;
  360. bytesArrived=AS_WaitPacket(file);
  361. if(bytesArrived<0)
  362.     {
  363.     if(file->af_SeekPastEOF)
  364.         {
  365.         bytesArrived=file->af_LastRes1;
  366.         file->af_BytesLeft=file->af_LastBytesLeft;
  367.         }
  368.     else return -1;
  369.     }
  370. if(file->af_ReadMode)
  371.     {
  372.     filePos=Seek(file->af_File,0,OFFSET_CURRENT);
  373.     if(filePos<0)
  374.         {
  375.         AS_RecordSyncFailure(file);
  376.         return -1;
  377.         }
  378.     current=filePos-(file->af_BytesLeft+bytesArrived)+file->af_SeekOffset;
  379.     if(mode==MODE_CURRENT) target=current+position;
  380.     else if(mode==MODE_START) target=position;
  381.     else 
  382.         {
  383.         if(!GetFileSize(file,&fileSize)) return -1;
  384.         target=fileSize+position;
  385.         }
  386.     minBuf=current-(LONG)(file->af_Offset-file->af_Buffers[1-file->af_CurrentBuf]);
  387.     maxBuf=current+file->af_BytesLeft+bytesArrived;
  388.     diff=target-current;
  389.     if((target<minBuf)||(target>=maxBuf))
  390.         {
  391.         if(target>=maxBuf)
  392.             {
  393.             if(!GetFileSize(file,&fileSize)) return -1;
  394.             if(target>fileSize)
  395.                 {
  396.                 file->af_SeekPastEOF=TRUE;
  397.                 SetIoErr(ERROR_SEEK_ERROR);
  398.                 AS_RecordSyncFailure(file);
  399.                 return -1;
  400.                 }
  401.             }
  402.         roundTarget=(target/file->af_BlockSize)*file->af_BlockSize;
  403.         if(Seek(file->af_File,roundTarget-filePos,OFFSET_CURRENT)<0)
  404.             {
  405.             AS_RecordSyncFailure(file);
  406.             return -1;
  407.             }
  408.         AS_SendPacket(file,file->af_Buffers[0]);
  409.         file->af_SeekOffset=target-roundTarget;
  410.         file->af_BytesLeft=0;
  411.         file->af_CurrentBuf=0;
  412.         file->af_Offset=file->af_Buffers[1];
  413.         }
  414.     else if((target<current)||(diff<=file->af_BytesLeft))
  415.         {
  416.         AS_RequeuePacket(file);
  417.         file->af_BytesLeft-=diff;
  418.         file->af_Offset+=diff;
  419.         if(file->af_SeekPastEOF) file->af_Packet.sp_Pkt.dp_Res1=file->af_LastRes1;
  420.         }
  421.     else
  422.         {
  423.         AS_SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]);
  424.         diff-=file->af_BytesLeft-file->af_SeekOffset;
  425.         file->af_Offset=file->af_Buffers[file->af_CurrentBuf]+diff;
  426.         file->af_BytesLeft=bytesArrived-diff;
  427.         file->af_SeekOffset=0;
  428.         file->af_CurrentBuf=1-file->af_CurrentBuf;
  429.         }
  430.     }
  431. else
  432.     {
  433.     if(file->af_BufferSize>file->af_BytesLeft)
  434.         {
  435.         if(Write(file->af_File,file->af_Buffers[file->af_CurrentBuf],file->af_BufferSize-file->af_BytesLeft)<0)
  436.             {
  437.             AS_RecordSyncFailure(file);
  438.             return -1;
  439.             }
  440.         }
  441.     current=Seek(file->af_File,position,mode);
  442.     if(current<0)
  443.         {
  444.         AS_RecordSyncFailure(file);
  445.         return -1;
  446.         }
  447.     file->af_BytesLeft=file->af_BufferSize;
  448.     file->af_CurrentBuf=0;
  449.     file->af_Offset=file->af_Buffers[0];
  450.     }
  451. if(file->af_SeekPastEOF) file->af_SeekPastEOF=FALSE;
  452. SetIoErr(0);
  453. return current;
  454. }
  455.  
  456. LONG WriteAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base)
  457. {
  458. LONG totalBytes=0;
  459. if(!file->af_Handler)
  460.     {
  461.     file->af_Offset=file->af_Buffers[0];
  462.     file->af_BytesLeft=file->af_BufferSize;
  463.     return numBytes;
  464.     }
  465. while(numBytes>file->af_BytesLeft)
  466.     {
  467.     if(file->af_BytesLeft)
  468.         {
  469.         CopyMem(buffer,file->af_Offset,file->af_BytesLeft);
  470.         numBytes-=file->af_BytesLeft;
  471.         buffer=(APTR)((ULONG)buffer+file->af_BytesLeft);
  472.         totalBytes+=file->af_BytesLeft;
  473.         }
  474.     if(AS_WaitPacket(file)<0) return -1;
  475.     AS_SendPacket(file,file->af_Buffers[file->af_CurrentBuf]);
  476.     file->af_CurrentBuf=1-file->af_CurrentBuf;
  477.     file->af_Offset=file->af_Buffers[file->af_CurrentBuf];
  478.     file->af_BytesLeft=file->af_BufferSize;
  479.     }
  480. CopyMem(buffer,file->af_Offset,numBytes);
  481. file->af_BytesLeft-=numBytes;
  482. file->af_Offset+=numBytes;
  483. return totalBytes+numBytes;
  484. }
  485.  
  486. LONG WriteCharAsync(register __a0 struct AsyncFile *file,register __d0 ULONG ch,register __a6 struct AsyncIOBase *base)
  487. {
  488. UBYTE    c;
  489. if(file->af_BytesLeft)
  490.     {
  491.     *file->af_Offset=ch;
  492.     --file->af_BytesLeft;
  493.     ++file->af_Offset;
  494.     return 1;
  495.     }
  496. c=ch;
  497. return WriteAsync(file,&c,1,base);
  498. }
  499.  
  500. LONG WriteLineAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR line,register __a6 struct AsyncIOBase *base)
  501. {
  502. return WriteAsync(file,line,strlen(line),base);
  503. }
  504.